﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

namespace FasterWPF
{
    public class GridSort : FasterWPF.CommonExt.ISortArgs
    {
        public GridSort(CommonExt.SortDataType sortDataType)
        {
            SortDataType=sortDataType;
        }

        public GridSort(CommonExt.SortDataType sortDataType, CommonExt.SortDataType sortDataType2)
        {
            SortDataType = sortDataType;
            SortDataType2 = sortDataType2;
        }
        
        public CommonExt.SortDataType SortDataType
        {
            get;
            set;
        }

        public CommonExt.SortDataType SortDataType2
        {
            get;
            set;
        }
    }

    public class GridArgs //: TwoParamArgs
    {
        public int Col
        {
            get;
            set;
        }

        public int Row
        {
            get;
            set;
        }

        public GridArgs(int row, int column)
           // : base(row, column)
        {
            Col = column;
            Row = row;
        }
    }
   
    public class GridParent : FasterWPF.IParent, ICanSort
    {         
        //this is ANA?
        public object Generate<T>(object chain, T args, Action<ContentControl> addUIElementsAction)
        {
            return chain;
        }

        #region IParent

        //this is BIND
        public object Add<T>(object chain, string key, T args, Border itemToAdd)
        {
            Grid g = (Grid)chain;
            g.Children.Add(itemToAdd);
            
            if (args is GridArgs)
            {
                Grid.SetColumn(itemToAdd, (args as GridArgs).Col);
                Grid.SetRow(itemToAdd, (args as GridArgs).Row);
            }

            return chain;
        }

        public void Remove(object chain, string key, Border itemToRemove)
        {
            ((Grid)chain).Children.Remove(itemToRemove); //remove from Grid

            IComposite ic = (IComposite)(((Grid)chain).GetIComposite<Grid>());
            ic.RemoveFromChain(itemToRemove);
        }

        public Dictionary<string, object> RetrieveDictionary(object chain)
        {
            return ((Grid)chain).GetCompositeLookupDictionary<Grid>();
        }
        
        //this is CATA?
        public List<Border> RetrieveCollection(object chain)
        {
            List<Border> lb = new List<Border>();
            foreach (var kvp in ((Grid)chain).GetCompositeLookupDictionary<Grid>())
            {
                lb.Add((Border)kvp.Value);
            }

            return lb;
        }

        #endregion

        public void ClearCollection(object chain)
        {
            IParent currentComposite = ((Grid)chain).GetSetting<Grid, IParent>("IParent");
            List<Border> gridItems = currentComposite.RetrieveCollection(chain);
             
            foreach (Border borItem in gridItems)
            {
               ((Grid)chain).Children.Remove(borItem); //remove from Grid
            }
        }

        public void BeforeSortCollection<T>(object chain, object args, int row, int column, FasterWPF.CommonExt.SortOrder sortOrder, CommonExt.SortControlType sortControlType)
             where T : FrameworkElement
        {
            var orderedKeys = ((Grid)chain).GetOrderedKeyList();
            var rows = ((Grid)chain).GetCompositeLookupDictionary();
            Dictionary<string, object> ChildLookupDict = ((Grid)chain).GetChildLookupDictionary();

            IParent currentComposite = ((Grid)chain).GetSetting<Grid, IParent>("IParent");
            List<Border> gridItemsUnOrdered = currentComposite.RetrieveCollection(chain);
            List<Border> gridItems = new List<Border>();
            foreach (string s in orderedKeys)
            {
                gridItems.Add(gridItemsUnOrdered.Where(b=>{return b.GetKey()==s;}).First());
            }
            //string one = gridItems[0].GetKey();
            //string two = gridItems[1].GetKey();
            //string three = gridItems[2].GetKey();

            List<int> initialOrderCol = new List<int>();
            List<int> initialOrderRow = new List<int>();
            List<string> initialOrderKey = new List<string>();
            //List<Border> newGridItemsOrder = new List<Border>();

            foreach (Border borC in gridItems)
            {
                initialOrderCol.Add(Grid.GetColumn(borC));
            }

            foreach (Border borR in gridItems)
            {
                initialOrderRow.Add(Grid.GetRow(borR));
            }

            foreach (Border borK in gridItems)
            {
                initialOrderKey.Add( borK.GetKey() );
            }

            if (gridItems != null && gridItems.Count > 0)
            {         
                    ClearCollection(chain);
                 
                    orderedKeys.Clear();

                    IEnumerable<string> items = null;

                    if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.DateTime)
                    {
                        items = CommonInternalExt.PerformSortOfKeysLevelOneDateTime<T>(row, column, sortOrder, ChildLookupDict, items, sortControlType);
                    }
                    else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.Decimal)
                    {
                        items = CommonInternalExt.PerformSortOfKeysLevelOneDecimal<T>(row, column, sortOrder, ChildLookupDict, items, sortControlType);
                    }
                    else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.Integer)
                    {
                        items = CommonInternalExt.PerformSortOfKeysLevelOneInteger<T>(row, column, sortOrder, ChildLookupDict, items, sortControlType);
                    }
                    else
                    {
                        //Default to String
                        items = CommonInternalExt.PerformSortOfKeysLevelOne<T>(row, column, sortOrder, ChildLookupDict, items, sortControlType);
                    }
        
                    List<string> itemsToList = items.ToList();
                    //IterHelpers.ApplyLoop(itemsToList.Count, j =>
                    //{
                    //     newGridItemsOrder.Add(null);
                    //});

                    IterHelpers.ApplyLoop(itemsToList.Count, j =>
                    {
                        String tempKey = (string)itemsToList[j];
                        Border tempBorder = gridItems[initialOrderKey.FindIndex(str => { return str == tempKey; })];
                        orderedKeys.Add(tempKey);

                        ((Grid)chain).Children.Add(tempBorder);

                        Grid.SetColumn(tempBorder, initialOrderCol[j]);
                        Grid.SetRow(tempBorder, initialOrderRow[j]);

                    });
            }                  
        }

        public void BeforeSortCollection1Then2<T>(object chain, object args, int row, int column, int row2, int column2, FasterWPF.CommonExt.SortOrder sortOrder, FasterWPF.CommonExt.SortOrder sortOrder2, CommonExt.SortControlType sortControlType)
  where T : FrameworkElement
        {
            var orderedKeys = ((Grid)chain).GetOrderedKeyList();
            var rows = ((Grid)chain).GetCompositeLookupDictionary();
            Dictionary<string, object> ChildLookupDict = ((Grid)chain).GetChildLookupDictionary();

            IParent currentComposite = ((Grid)chain).GetSetting<Grid, IParent>("IParent");
            List<Border> gridItemsUnOrdered = currentComposite.RetrieveCollection(chain);
            List<Border> gridItems = new List<Border>();
            foreach (string s in orderedKeys)
            {
                gridItems.Add(gridItemsUnOrdered.Where(b => { return b.GetKey() == s; }).First());
            }

            List<int> initialOrderCol = new List<int>();
            List<int> initialOrderRow = new List<int>();
            List<string> initialOrderKey = new List<string>();
            
            foreach (Border borC in gridItems)
            {
                initialOrderCol.Add(Grid.GetColumn(borC));
            }

            foreach (Border borR in gridItems)
            {
                initialOrderRow.Add(Grid.GetRow(borR));
            }

            foreach (Border borK in gridItems)
            {
                initialOrderKey.Add(borK.GetKey());
            }

            if (gridItems != null && gridItems.Count > 0)
            {
                ClearCollection(chain);

                Dictionary<string, Tuple<object, object>> sourceToSortOn = new Dictionary<string, Tuple<object, object>>();

                string defaultNullValue = null;
                string defaultNullValue2 = null;

                if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType)==FasterWPF.CommonExt.SortDataType.DateTime)
                {
                    defaultNullValue = "1/1/1900";
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.Decimal)
                {
                    defaultNullValue = "0.00";
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.Integer)
                {
                    defaultNullValue = "0";
                }
                else
                {
                    defaultNullValue = "";
                }

                if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType2) == FasterWPF.CommonExt.SortDataType.DateTime)
                {
                    defaultNullValue2 = "1/1/1900";
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType2) == FasterWPF.CommonExt.SortDataType.Decimal)
                {
                    defaultNullValue2 = "0.00";
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType2) == FasterWPF.CommonExt.SortDataType.Integer)
                {
                    defaultNullValue2 = "0";
                }
                else
                {
                    defaultNullValue2 = "";
                }

                CommonInternalExt.SetDefaultsForTextElementsAtRowCol<Grid>(chain, row, column, row2, column2, sortControlType, orderedKeys, sourceToSortOn, defaultNullValue, defaultNullValue2);
                
                orderedKeys.Clear();

                IOrderedEnumerable<KeyValuePair<string, Tuple<object, object>>> items = null;
                
                Type dataType1 = null;
                Type dataType2 = null;

                if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.DateTime)
                {
                    dataType1 = typeof(DateTime);
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.Decimal)
                {
                    dataType1 = typeof(Decimal);
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.Integer)
                {
                    dataType1 = typeof(Int32);
                }
                else
                {
                    dataType1 = typeof(String);
                }

                if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType2) == FasterWPF.CommonExt.SortDataType.DateTime)
                {
                    dataType2 = typeof(DateTime);
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType2) == FasterWPF.CommonExt.SortDataType.Decimal)
                {
                    dataType2 = typeof(Decimal);
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType2) == FasterWPF.CommonExt.SortDataType.Integer)
                {
                    dataType2 = typeof(Int32);
                }
                else
                {
                    dataType2 = typeof(String);
                }

                items = CommonInternalExt.PerformSortOfKeysLevelTwo(chain, sortOrder, sortOrder2, sourceToSortOn, items, dataType1, dataType2);

                List<KeyValuePair<string, Tuple<object, object>>> itemsToList = items.ToList();

                IterHelpers.ApplyLoop(itemsToList.Count, j =>
                {
                    String tempKey = ((KeyValuePair<string, Tuple<object, object>>)itemsToList[j]).Key.ToString();
                    Border tempBorder = gridItems[initialOrderKey.FindIndex(str => { return str == tempKey; })];
                    orderedKeys.Add(tempKey);

                    ((Grid)chain).Children.Add(tempBorder);

                    Grid.SetColumn(tempBorder, initialOrderCol[j]);
                    Grid.SetRow(tempBorder, initialOrderRow[j]);
                });
            }    
        }

        public void AfterSortCollection<T>(object chain)
             where T : FrameworkElement
        { }

        public void InnerSortCollection(object chain, int row, int column, string key, ref int counter, Border itemToReAdd)
        {
            throw new NotImplementedException();
        }
        
        public void SetSelected(object chain, Border itemToSetAsSelected)
        {
        }
    }//end of class
}//end of namespace
